#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;

// int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
//                   void *(*start_routine) (void *), void *arg)
// thread: 线程id，输出型参数，调用create传值回来，pthread_t是无符号的参数
// attr:线程的属性,一般设置为nullptr,默认属性
// void *(*start_routine) (void *): 是一个函数指针，是线程的入口函数，主函数通过回调strar_routine执行线程代码
//                                  参数为void*,返回值为void*,的函数指针
// arg：参数,arg会作为参数传递给回调函数start_routine时
// 创建成功返回0，失败返回-1

//--------------1.pthread_create------------------------

// void* routine_thread(void* args)
// {
//     while(true)
//     {
//         cout << "this is a new pthread" << endl;
//         sleep(1);
//     }
// return nullptr;
// }

// int main()
// {
//     pthread_t t;
//     pthread_create(&t,nullptr,routine_pthread,nullptr);
//     while(true)
//     {
//         cout << "this is a main pthread" << endl;
//         sleep(1);
//     }
//     return 0;
// }

// ----------------- 2. 传递参数arg    3.pthread_join ------------------

//  int pthread_join(pthread_t thread, void **retval);
//  pthread:线程id
//  retval: 是一个输出型参数，拿到子线程的退出结果，返回0成功，其他值失败，需要获取你可以传值，不需要则使用nullptr
//  一个线程创建出来要去被等待，否则就会存在类似僵尸进程的问题
// #define NUM 4
// void* routine_thread(void* args)
// {
//     char* name = (char*)args;
//     while(true)
//     {
//         cout << "this is a new pthread,my name is " << name << endl;
//         sleep(1);
//     }
//     return nullptr;
// }

// int main()
// {
//     pthread_t t[NUM];
//     for(int i = 0; i < NUM; i++)
//     {
//         // char name[64] = { 0 }; //bug ?  要注意使用的多线程，资源都是共享的，将name传进去，多个线程使用的是同一个name，并不是各自拥有的。
//         // snprintf(name,sizeof(name),"pthread-%d",i);

//         char* name = new char[64]; //让每一个线程都独自拥有一个name
//         int len = 64;
//         snprintf(name,len,"pthread-%d",i);
//         pthread_create(t+i,nullptr,routine_thread,name);
//     }
//     //没有这个while(true) 执行程序没有任何结果，原因是主线程结束了，
//     //意味着进程结束，整个资源都被释放，线程也就不会执行
//     //想要暂停，除了用while(true)这个，会显得不太合理，正确的是要去等待其他线程的退出。即使用join
//     //1. while
//     // while(true)
//     // {
//     //     cout << "this is main thread" << endl;
//     //     sleep(1);
//     // }
//     //2. jion
//     for(int i = 0; i < NUM; i++)
//     {
//         pthread_join(t[i],nullptr);
//     }
//     cout << "main thread wait successful" << endl;  //通过执行程序可知，join是阻塞等待
//     return 0;
// }

// -----------------------4. pthread_exit()  5.pthread_cancel()  6. pthread_join() 7.pthread_detach()
// void pthread_exit(void *retval);
// 作用：终止线程，带回返回值 retval

// int pthread_cancel(pthread_t thread);
// 作用：终止线程thread

// int pthread_detach(pthread_t thread);
// 作用：与主线程分离，系统自动回收线程thread，主线程不需要join

// pthread_t pthread_self(void);
// 作用：获取线程自己的id

// Task: 使用多线程，完成从1累加到100，并待会返回值
// 当子线程要把参数传回给主线程的时候，要注意到变量的生命周期，因此是不能返回栈上的数据

// void* routine_thread(void* args)
// {
//     cout << "args = " << args << endl;
//     int n = *((int*)args);
//     int64_t* sum = new int64_t(0);
//     cout << "sum = " << sum << endl;
//     for(int i = 1; i < n; i++)
//     {
//         *sum += i;
//     }
//     // return (void*) sum;     // ok
//     pthread_exit((void*)sum);  // ok
//     // return  <==> pthread_exit();
// }

// int main()
// {
//     pthread_t t;
//     int N = 100;
//     cout << "&N = " << &N << endl;
//     pthread_create(&t,nullptr,routine_thread,(void*)&N);
//     // pthread_create(&t,nullptr,routine_thread,(void*)100);  // error
//     void* ret = nullptr;
//     pthread_join(t,&ret);
//     cout << *((int64_t*)ret) << endl << "ret = " << ret << endl;
//     return 0;
// }

// --------------------------------------------------------------------------------

// Task: 简单使用传参

// void* routine_thread(void* args)
// {
//     const char* name = static_cast<const char*>(args);
//     int cnt = 5;
//     while(cnt)
//     {
//         cout << name << "is running " << cnt-- << endl;
//         sleep(1);
//     }
//     // pthread_exit((void*)11);
//     return (void*) 11;
// }

// int main()
// {
//     pthread_t t;
//     pthread_create(&t,nullptr,routine_thread,(void*)"thread 1");
//     void* ret = nullptr;
//     pthread_join(t,&ret);
//     cout << "new thread exit : " << (int64_t)ret << endl;
//     return 0;
// }

// --------------------------------------------------------------------

// Task: 传递的参数，并不局限于不普通的变量，也可以是类！
// 求1-_top的和，使用多线程并封装成类

// class Task
// {
// public:
//     // 任务需求
//     int _top;

//     // 接收子线程的返回值
//     int _sum;
//     int _ret; // 退出码 0 - ok, -1 - error

//     Task( int top = 100, int sum = 0, int ret = 0)
//         : _top(top),
//           _sum(sum),
//           _ret(ret)
//     {

//     }
// };

// void* routine_thread(void* args)
// {
//     Task* t = static_cast<Task*>(args); //安全的类型转换
//     cout << "t = " << t << endl;
//     for(int i = 1; i <= t->_top; i++)
//     {
//         t->_sum += i;
//     }
//     t->_ret = 0;
//     return (void*)t;  //这个t实际上是主线程那个t的地址
// }

// int main()
// {
//     pthread_t t;
//     Task ta;
//     cout << "&ta = " << &ta << endl;

//     pthread_create(&t,nullptr,routine_thread,&ta);

//     void* ret = nullptr;

//     // pthread_join(t,(void**)ret);
//     pthread_join(t,&ret);  //join第二个参数的类型是void**,说明是一个void*的地址，所以是取地址，它是作为一个输出型参数

//     cout << "ret = " << ret << endl;

//     cout << "运行结果为 " << ((Task*)ret)->_sum << endl;
//     return 0;
// }

// --------------------------------------------------------------------------------------

// Task：创建多个线程，完成多个累加和的任务

// 将类多一下设计，比如线程的名字，线程创建的时间，线程的状态

class Task
{
public:
    // 任务需求
    int _top;

    // 接收子线程的返回值
    int _sum;
    int _ret; // 退出码 0 - ok, -1 - error

    // 线程的属性
    string _name;
    time_t _creatTime;
    pthread_t _id;

    Task( string name, int top = 100) // 缺省值得靠右
        : _top(top),
          _sum(0),
          _ret(0),
          _name(name)
    {
        _creatTime = time(nullptr);
    }
};

void *routine_thread(void *args)
{
    Task *t = static_cast<Task *>(args); // 安全的类型转换
    for (int i = 1; i <= t->_top; i++)
    {
        t->_sum += i;
    }
    cout << t->_name << "calculate done..." << endl;
    return (void *)t; // 这个t实际上是主线程那个t的地址
}

int main()
{
    int N = 4;
    pthread_t t[N];
    for (int i = 0; i < N; i++)
    {
        // char* name = new char(64);   // error --> ()这个是给char 赋初值
        char *name = new char[64];
        snprintf(name, 64, "thread - %d", i);
        Task *ta = new Task(name, 100 + 5 * i);
        pthread_create(t + i, nullptr, routine_thread, ta);
    }

    for(int i = 0; i < N; i++)
    {
        void *ret = nullptr;
        pthread_join(t[i], &ret);
        cout << ((Task *)ret)->_name << "的运行结果为 " << ((Task *)ret)->_sum << endl;
    }

    return 0;
}
